/*
 * This file is part of the OSMembrane project.
 * More informations under www.osmembrane.de
 * 
 * The project is licensed under the GNU GENERAL PUBLIC LICENSE 3.0.
 * for more details about the license see http://www.osmembrane.de/license/
 * 
 * Source: $HeadURL: http://osmembrane-gui.googlecode.com/svn/sources/src/de/osmembrane/view/panels/DisplayTemplatePanel.java $ ($Revision: 902 $)
 * Last changed: $Date: 2011-03-09 17:41:55 +0000 (Wed, 09 Mar 2011) $
 */



package de.osmembrane.view.panels;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

/**
 * A {@link JPanel} component with the ability to create colored {@link Image}s
 * with icons from an {@link ImageIcon} display template.
 * 
 * To create a displayable {@link Image}, just call
 * {@link DisplayTemplatePanel#derivateDisplay} with the desired {@link Color}
 * and icon.
 * 
 * Howsoever it is capable of pre-rendering all objects necessary into a map and
 * get them out once they're needed without any extra overhead.
 * 
 * <b>It is recommended you use the static ability of prerendering since that
 * will save a lot of memory and processing power.</b>
 * 
 * @author tobias_kuhn
 * 
 */
public abstract class DisplayTemplatePanel extends JPanel {

	protected static final long serialVersionUID = -2046897951374601603L;

	/**
	 * Map used for the prerendered objects.
	 */
	private static Map<Object, List<Image>> prerender;

	/**
	 * Internal {@link DisplayTemplatePanel} for prerendering.
	 * (derivateDisplay() calls are only possible on instances)
	 */
	private static DisplayTemplatePanel prerenderPanel;

	/**
	 * Renders the correct pre-rendered display image based on template in the
	 * given color and with the given icon.
	 * 
	 * @param template
	 *            the ImageIcon to colorize and iconify
	 * @param color
	 *            The Color this image shall display in
	 * @param icon
	 *            The icon this image shall display
	 * @return the pre-rendered Image in the color and with the icon
	 */
	protected Image derivateDisplay(ImageIcon template, Color color, Image icon) {
		// copy displayTemplate to a BufferedImage
		BufferedImage result = new BufferedImage(template.getIconWidth(),
				template.getIconHeight(), BufferedImage.TYPE_4BYTE_ABGR);

		Graphics2D g = result.createGraphics();
		g.drawImage(template.getImage(), 0, 0, this);

		WritableRaster r = result.getRaster();

		// Scan the lines with a float multiplication
		float[] colorRGB = color.getColorComponents(null);
		float[] pixelRow = new float[4 * result.getWidth()];

		for (int y = 0; y < result.getHeight(); y++) {
			r.getPixels(0, y, result.getWidth() - 1, 1, pixelRow);

			for (int x = 0; x < result.getWidth(); x++) {
				pixelRow[4 * x + 0] *= colorRGB[0];
				pixelRow[4 * x + 1] *= colorRGB[1];
				pixelRow[4 * x + 2] *= colorRGB[2];
			}

			r.setPixels(0, y, result.getWidth() - 1, 1, pixelRow);
		}

		// place the icon
		if (icon != null) {
			g.drawImage(icon, getWidth() - (icon.getWidth(this) / 2),
					getHeight() - (icon.getHeight(this) / 2), this);
		}

		return result;
	}

	/**
	 * Calls
	 * {@link DisplayTemplatePanel#derivateDisplay(ImageIcon, Color, Image)} for
	 * the object forObject and stores it in the list for forObject for quick
	 * further access.
	 * 
	 * If there is already an image stored for forObject, it is overwritten. You
	 * can easily test this by checking
	 * {@link DisplayTemplatePanel#givePrerender(Object)} == null.
	 * 
	 * @param forObject
	 *            object to identify the prerendering
	 * @see #derivateDisplay(ImageIcon, Color, Image)
	 * @return the immediately created Image
	 */
	protected static Image prerenderDisplay(Object forObject,
			ImageIcon template, Color color, Image icon) {
		if (prerender == null) {
			prerender = new HashMap<Object, List<Image>>();
		}
		if (prerenderPanel == null) {
			prerenderPanel = new DisplayTemplatePanel() {
				private static final long serialVersionUID = -8556169733942717510L;
			};
		}

		if (prerender.get(forObject) == null) {
			prerender.put(forObject, new ArrayList<Image>());
		}
		Image created = prerenderPanel.derivateDisplay(template, color, icon);
		prerender.get(forObject).add(created);
		return created;
	}

	/**
	 * Returns the prerendered {@link Image} created for forObject
	 * 
	 * @param forObject
	 *            object to identify the prerendering
	 * @return the prerendered images for forObject, or null if none exists
	 */
	protected static List<Image> givePrerender(Object forObject) {
		return (prerender != null) ? prerender.get(forObject) : null;
	}

}
